home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / printing / bjf-1.000 / bjf-1 / bjf / bj.c < prev    next >
C/C++ Source or Header  |  1994-03-27  |  13KB  |  557 lines

  1. /* 
  2.  * Copyright 1994 Chris Smith
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and its
  5.  * documentation for any purpose and without fee is hereby granted,
  6.  * provided that the above copyright notice appears in all copies and that
  7.  * both that copyright notice and this permission notice appears in
  8.  * supporting documentation.  I make no representations about the
  9.  * suitability of this software for any purpose.  It is provided "as is"
  10.  * without express or implied warranty.
  11.  */
  12.  
  13. /* Canon escape sequence grunge.
  14.  
  15.    2-up, 4-up, and landscape printing are done with downloaded fonts.
  16.    I've tried three approaches:
  17.     1. Just download the font and print
  18.     2. Rasterize a whole page and send graphics
  19.     3. Download character pairs and print two lines at a time
  20.  
  21.    #1 is simplest, and the print head moves at full speed.  But the paper
  22.    advances slowly, because the characters are small.
  23.  
  24.    #2 is slow.  You don't get bidirectional printing, and it eats CPU time.
  25.  
  26.    #3 is the current implementation.  It does not keep the print head
  27.    moving at full speed, because the volume of data is too large.  But
  28.    it does print bidirectionally.  It is, net, the fastest.
  29.  
  30.    A hash table is used to map character pairs to single-char codes,
  31.    e.g., the pair "th" might be downloaded as a two-character glyph
  32.    for the character 'X'.  Then all occurrences of "th" are printed
  33.    by sending 'X'.
  34.  
  35.    There's only room for 100-200 different glyphs, after which we
  36.    flush the font memory in the printer and start over.  Doing this in
  37.    the middle of a line makes the print head shoot over to the margin
  38.    and then back, which increases wear&tear, so we only do font flushes
  39.    at line breaks.  That requires two passes over each line pair, one
  40.    to download any necessary glyphs, one to send the codes for the
  41.    character pairs.
  42.  
  43.    For documents printed with device fonts none of this nonsense is
  44.    necessary. */
  45.  
  46.  
  47. #include "bj.h"
  48. #include <assert.h>
  49. #include <stdio.h>
  50. #include <string.h>
  51.  
  52. /* Handy abbrevs */
  53.  
  54. #define put1(c) putchar (c)
  55. #define put2b(w) (put1 ((w) >> 8), put1 (w))
  56. #define put2l(w) (put1 (w), put1 ((w) >> 8))
  57.  
  58. /* Option bits for ESC I command */
  59.  
  60. #define DRAFT    0
  61. #define LQ    2
  62.  
  63. #define CPI10    0
  64. #define CPI12    8
  65. #define CPI17    16
  66. #define CPIPS    1
  67.  
  68. #define RESIDENT 0
  69. #define DOWNLOAD 4
  70.  
  71. /* Magic numbers for ESC [ I command */
  72.  
  73. struct fontid
  74. {
  75.   char *tag;
  76.   int fid[4];
  77. };
  78.  
  79. static const struct fontid fontid[] =
  80. {
  81.   /*        cpi = 10  12  17   ps */
  82.   { "courier",  { 11, 85, 254, 171 }},
  83.   { "gothic",    { 36, 87, 255, 174 }},
  84.   { "prestige",    { 12, 86, 256, 164 }},
  85. };
  86.  
  87. /* Overstrike replacements in BJ (standard PC) char set */
  88.  
  89. #define LSQ '\''
  90. #define RSQ '`'
  91.  
  92. static const uchar overstrike_replacement[][3] =
  93. {
  94.   { 'e', LSQ, 130 },
  95.   { 'a', RSQ, 133 },
  96.   { 'e', RSQ, 138 },
  97.   { 'i', RSQ, 141 },
  98.   { 'E', RSQ, 144 },
  99.   { 'o', RSQ, 149 },
  100.   { 'u', RSQ, 151 },
  101.   { 'a', LSQ, 160 },
  102.   { 'i', RSQ, 161 },
  103.   { 'o', RSQ, 162 },
  104.   { 'u', RSQ, 163 },
  105.   { 'n', '~', 164 },
  106.   { 'N', '~', 165 },
  107.   { '+', '_', 241 },
  108.   { '>', '_', 242 },
  109.   { '<', '_', 243 },
  110. };
  111.  
  112. /* downloadable fonts */
  113. extern uchar port_17x24[];
  114. extern uchar land_37x22[];
  115. extern uchar land_45x24[];
  116.  
  117. /* selected downloadable font, if needed */
  118. uchar *myfont;
  119. uchar *ch_bitmap[256];
  120.  
  121. /* Manual suggests that there is a 32K limit on downloaded bit maps.
  122.    We flush download memory and start over it fills up. */
  123. static int n_downloads_left;
  124.  
  125. /* Hash table of downloaded character pairs.
  126.    The hash index is the single char code the pair is downloaded into. */
  127.  
  128. struct hash {
  129.   unsigned char c1, c2;
  130.   unsigned valid:1, reserved:1, downloaded:1, quoted:1;
  131. };
  132.  
  133. struct hash hash[256];
  134.  
  135. static void init_hash (void);
  136. static void flush_font (void);
  137. static int hash_pair (uchar c1, uchar c2);
  138. static void send_glyph (uchar c);
  139. static void unpack_myfont (void);
  140.  
  141. /* Buffer holding a line pair to be printed in one pass */
  142. static uchar line1[MAXCOL], line2[MAXCOL];
  143. static int coln;
  144.  
  145. /* Bit sieve for making draft glyphs */
  146. unsigned draft_mask;
  147.  
  148. int check_font_name (const char *name)
  149. {
  150.   int n;
  151.  
  152.   if (name == 0)
  153.     return 1;
  154.  
  155.   for (n = 0; n < sizeof fontid / sizeof *fontid; n++)
  156.     if (! strcasecmp (name, fontid[n].tag))
  157.       return 1;
  158.  
  159.   return 0;
  160. }
  161.  
  162. void init_font (int lflag, int x2flag, int x4flag)
  163. {
  164.   if (lflag)
  165.     myfont = land_45x24;
  166.   else if (x2flag)
  167.     myfont = land_37x22;
  168.   else if (x4flag)
  169.     myfont = port_17x24;
  170.   else
  171.     myfont = 0;
  172.  
  173.   if (myfont)
  174.     unpack_myfont ();
  175. }
  176.  
  177. void do_init (const char *font, int cpi, int code_page, int draft,
  178.           float lpi, float page_length)
  179. {
  180.   if (myfont)
  181.     init_hash ();
  182.  
  183.   /* set draft bit mask for font downloads */
  184.   if (draft)
  185.     draft_mask = 0xaaaaaaaa;
  186.   else
  187.     draft_mask = -1;
  188.  
  189.   /* basic init string, everything off except \n -> crlf */
  190.   fwrite ("\033[K\004\000\001\044\020\000", 9, 1, stdout);
  191.  
  192.   /* initialize download memory so ESC [ I font selection works. */
  193.   fwrite ("\033=\001\000\045", 5, 1, stdout);
  194.  
  195.   /* download space so printer will honor request to select download font */
  196.   if (myfont)
  197.     send_glyph (hash_pair (' ', ' '));
  198.  
  199.   /* set font */
  200.  
  201.   if (! font) {
  202.     int opts = 0;
  203.  
  204.     switch (cpi) {
  205.     case 10: opts |= CPI10;
  206.     when 12: opts |= CPI12;
  207.     when 17: opts |= CPI17;
  208.     when -1: opts |= CPIPS; }
  209.  
  210.     if (draft)
  211.       opts |= DRAFT;
  212.     else
  213.       opts |= LQ;
  214.  
  215.     /* set the chosen char pitch and draft/LQ mode */
  216.     if (! myfont) {
  217.       put1 ('\033'); put1 ('I'); put1 (opts); }
  218.     else {
  219.       fwrite ("\033I\007\033[I\005\000\000\000\000\000\002\0337",
  220.           15, 1, stdout); }}
  221.   else {
  222.     int n, ix;
  223.  
  224.     for (n = 0; n < sizeof fontid / sizeof *fontid; n++)
  225.       if (! strcasecmp (font, fontid[n].tag))
  226.     break;
  227.  
  228.     switch (cpi) {
  229.     case 10: ix = 0;
  230.     when 12: ix = 1;
  231.     when 17: ix = 2;
  232.     when -1: ix = 3; }
  233.  
  234.     put1 ('\033'); put1 ('['); put1 ('I');
  235.     put2l (5);
  236.     put2b (fontid[n].fid[ix]);
  237.     put2b (cpi == -1 ? 0 : 1440 / cpi);
  238.     put1 (cpi == -1 ? 2 : 1); }
  239.  
  240.   /* set code page */
  241.  
  242.   if (code_page && code_page != 437) {
  243.     put1 ('\033'); put1 ('['); put1 ('T');
  244.     put2l (4);
  245.     put2b (0);
  246.     put2b (code_page); }
  247.     
  248.   /* set baselineskip */
  249.  
  250.   if (lpi != 6 || myfont) {
  251.     int baselineskip;
  252.  
  253.     if (myfont)
  254.       baselineskip = myfont[1];
  255.     else
  256.       baselineskip = 0.5 + 360.0 / lpi;
  257.  
  258.     put1 ('\033'); put1 ('['); put1 ('\\');
  259.     put2l (4);
  260.     put2l (0);
  261.     put2l (360);
  262.  
  263.     put1 ('\033'); put1 ('3'); put1 (baselineskip);
  264.   }
  265. }
  266.  
  267. void do_fin ()
  268. {
  269.   const char *fin;
  270.   int len;
  271.   fin_string (&fin, &len);
  272.   fwrite (fin, 1, len, stdout);
  273. }
  274.  
  275. void fin_string (const char **string, int *len)
  276. {
  277.   /* Reset to dip switch settings.  Reset download memory to resident fonts. */
  278.   static const char fin[] = "\033[K\004\000\001\044\200\200";
  279.  
  280.   *string = fin;
  281.   *len = sizeof fin - 1;
  282. }
  283.  
  284. void do_hskip (int pos)
  285. {
  286.   if (pos) {
  287.     put1 ('\033');
  288.     put1 ('d');
  289.     put2l (pos);
  290.   }
  291. }
  292.  
  293. void send_quoted (uchar c)
  294. {
  295.   put1 ('\033'), put1 ('^');
  296.   put1 (c);
  297. }
  298.  
  299. void bold_on ()
  300. {
  301.   put1 ('\033'), put1 ('G');
  302. }
  303.  
  304. void bold_off ()
  305. {
  306.   put1 ('\033'), put1 ('H');
  307. }
  308.  
  309. void underline_on ()
  310. {
  311.   put1 ('\033'), put1 ('-'), put1 ('1');
  312. }
  313.  
  314. void underline_off ()
  315. {
  316.   put1 ('\033'), put1 ('-'), put1 ('0');
  317. }
  318.  
  319. uchar replace_overstrike (uchar a, uchar b)
  320. {
  321.   int n;
  322.   int nov = sizeof overstrike_replacement / sizeof *overstrike_replacement;
  323.  
  324.   for (n = 0; n < nov; n++)
  325.     if ((overstrike_replacement[n][0] == a
  326.      && overstrike_replacement[n][1] == b)
  327.     || (overstrike_replacement[n][0] == b
  328.         && overstrike_replacement[n][1] == a))
  329.       return overstrike_replacement[n][2];
  330.   return 0;
  331. }
  332.  
  333. /* All this grief exists so we can produce this: a sequence of font
  334.    download commands that define char-above-char glyphs for the line
  335.    pair, followed by a string of char codes using the defined glyphs.
  336.    It would be much easier just to send each glyph right before using
  337.    it, or to output the data in graphics mode, but neither method
  338.    prints smoothly and bidirectionally. */
  339.  
  340. void send_pair (uchar c1, uchar c2)
  341. {
  342.   line1[coln] = c1;
  343.   line2[coln] = c2;
  344.   coln++;
  345. }
  346.  
  347. void send_linebuf (int hskip)
  348. {
  349.   int n, c;
  350.   uchar line[MAXCOL];
  351.  
  352.   /* see if the already-downloaded glyphs plus any new ones needed for
  353.      this line pair will fit into the printer's memory. */
  354.  again:
  355.   for (n = 0; n < coln; n++) {
  356.     c = hash_pair (line1[n], line2[n]);
  357.     if (c == -1) {
  358.       /* No.  Flush the printer font cache and start again.  The printer
  359.      memory will hold at least one line, so we will succeed next time. */
  360.       flush_font ();
  361.       goto again; }
  362.     else
  363.       line[n] = c; }
  364.  
  365.   /* ok, now download the new glyphs needed by this line pair. */
  366.  
  367.   for (n = 0; n < coln; n++) {
  368.     c = line[n];
  369.     if (! hash[c].downloaded)
  370.       send_glyph (c); }
  371.  
  372.   /* now transmit the line pair using the two-char glyphs. */
  373.  
  374.   do_hskip (hskip);
  375.   for (n = 0; n < coln; n++) {
  376.     c = line[n];
  377.     if (hash[c].quoted)
  378.       put1 ('\033'), put1 ('^');
  379.     put1 (c); }
  380.  
  381.   /* reset coln for next time. */
  382.   coln = 0;
  383. }
  384.  
  385. static void flush_font ()
  386. {
  387.   init_hash ();
  388.   fwrite ("\033=\001\000\045", 5, 1, stdout);
  389.   send_glyph (hash_pair (' ', ' '));
  390. }
  391.  
  392. static void init_hash ()
  393. {
  394.   uchar c;
  395.  
  396.   memset (hash, 0, sizeof hash);
  397.  
  398.   for (c = 0; c < 040; c++)
  399.     hash[c].quoted = 1;
  400.   for (c = 0177; c < 0240; c++)
  401.     hash[c].quoted = 1;
  402.  
  403.   hash['\n'].reserved = hash['\n'].valid = 1;
  404.   hash['\f'].reserved = hash['\f'].valid = 1;
  405.   hash['\033'].reserved = hash['\033'].valid = 1;
  406.  
  407.   /* each download takes 6 bytes per column, 6 * width bytes total. */
  408.   n_downloads_left = 32768 / (6 * myfont[0]);
  409.  
  410.   /* it also takes one of the 253 char slots */
  411.   if (n_downloads_left > 252)
  412.     n_downloads_left = 252;
  413. }
  414.  
  415. /* hash the character pair (c1,c2) and return the char code to use for it.
  416.    if there is no space for a new code, return -1. */
  417.  
  418. static int hash_pair (uchar c1, uchar c2)
  419. {
  420.   unsigned h = (c1 * 0x9e9f) ^ (c2 * 0x0a01);
  421.   unsigned ix = (h >> 8) & 255;
  422.   unsigned dix;
  423.  
  424.   if (hash[ix].valid) {
  425.     if (hash[ix].c1 == c1 && hash[ix].c2 == c2 && ! hash[ix].reserved)
  426.       return ix;
  427.     dix = h | 1;
  428.  
  429.     for (;;) {
  430.       ix = (ix + dix) & 255;
  431.       if (hash[ix].c1 == c1 && hash[ix].c2 == c2 && ! hash[ix].reserved)
  432.     return ix;
  433.       if (! hash[ix].valid)
  434.     break;
  435.     }
  436.   }
  437.  
  438.   if (n_downloads_left == 0)
  439.     return -1;
  440.   n_downloads_left--;
  441.  
  442.   hash[ix].c1 = c1; hash[ix].c2 = c2; hash[ix].valid = 1;
  443.   return ix;
  444. }
  445.  
  446. static void send_glyph (uchar c)
  447. {
  448.   uchar *ch1 = ch_bitmap[hash[c].c1];
  449.   uchar *ch2 = ch_bitmap[hash[c].c2];
  450.   int pxlw = myfont[0];
  451.   unsigned fourbytes, mask;
  452.   int x, nsh;
  453.  
  454.   /* mark downloaded */
  455.   hash[c].downloaded = 1;
  456.  
  457.   /* download command */
  458.   put1 ('\033'); put1 ('=');
  459.  
  460.   /* length of following data */
  461.   put2l (11 + 6 * pxlw);
  462.  
  463.   /* printer id: bj 200 */
  464.   put1 (37);
  465.  
  466.   /* code page, 437 */
  467.   put2b (437);
  468.  
  469.   /* font id 0 */
  470.   put2b (0);
  471.  
  472.   /* char set 1, proportional */
  473.   put1 (0x10);
  474.  
  475.   /* gratuitious null */
  476.   put1 (0);
  477.  
  478.   /* char code */
  479.   put1 (c);
  480.  
  481.   /* char edit attributes (line drawing, etc): none */
  482.   put1 (0);
  483.  
  484.   /* char width, dots */
  485.   put1 (pxlw);
  486.  
  487.   /* gratuitous null */
  488.   put1 (0);
  489.  
  490.   /* get mask for sieving glyph for draft mode */
  491.   mask = draft_mask;
  492.  
  493.   /* [must write more code to handle case where cell width isn't 3 bytes] */
  494.   assert (16 < myfont[1] && myfont[1] <= 24);
  495.   nsh = 24 - myfont[1];
  496.  
  497.   /* send pxlw columns, 6 bytes each, msb first */
  498.   for (x = 0; x < pxlw; x++) {
  499.     /* first two bytes come from top char */
  500.     put1 (ch1[0] & mask);
  501.     put1 (ch1[1] & mask);
  502.  
  503.     /* the last four include the bottom char, shifted up nsh */ 
  504.     fourbytes = (ch1[2] << 24
  505.          | ch2[0] << (nsh + 16)
  506.          | ch2[1] << (nsh + 8)
  507.          | ch2[2] << nsh);
  508.     fourbytes &= mask;
  509.     put1 (fourbytes >> 24);
  510.     put1 (fourbytes >> 16);
  511.     put1 (fourbytes >> 8);
  512.     put1 (fourbytes >> 0);
  513.  
  514.     if (mask != -1)
  515.       mask = ~mask;
  516.  
  517.     ch1 += 3;
  518.     ch2 += 3;
  519.   }
  520. }
  521.  
  522. static void unpack_myfont ()
  523. {
  524.   int c, pxlw, pxlh, bytes_per_bitmap;
  525.   uchar *ch, *ch_space;
  526.  
  527.   bzero (ch_bitmap, sizeof ch_bitmap);
  528.  
  529.   /* char cell dimensions are stored in the first two bytes.  this is
  530.      followed by a sequence of one or more char specs and then a zero
  531.      byte.  a char spec is a char code, one byte, followed by the bit
  532.      map for the char.  the bitmaps are stored by columns, leftmost
  533.      first, pxlh bits per column, pxlw columns.  each column starts on
  534.      a byte boundary. */
  535.  
  536.   pxlw = myfont[0];
  537.   pxlh = myfont[1];
  538.   bytes_per_bitmap = ((pxlh + 7) >> 3) * pxlw;
  539.  
  540.   /* store a pointer to the bitmap for each char c in ch_bitmap[c] */
  541.  
  542.   ch = myfont + 2;
  543.   do {
  544.     c = ch[0];
  545.     if (c == ' ')
  546.       ch_space = ch;
  547.     ch_bitmap[c] = ch = ch + 1;
  548.     ch += bytes_per_bitmap;
  549.   } while (*ch != 0);
  550.  
  551.   /* point undefined chars to space, so there will be some bitmap
  552.      for every char code. */
  553.   for (c = 0; c < 256; c++)
  554.     if (! ch_bitmap[c])
  555.       ch_bitmap[c] = ch_space;
  556. }
  557.